package cn.jdy.framework.db.mongodb;

import java.util.List;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MapReduceOutput;
import cn.jdy.framework.exception.BaseException;

/**
 * mongoDB 基础操作实现类 mongoDB 基础操作实现类
 * 
 * @author wuzhiliang
 * @date 2013-07-01
 * 
 */
public class MongoDBService {

  private DB db;// 数据库连接

  /**
   * 给mongoDB 插入数据 给mongoDB 插入数据
   * 
   * @param collection
   *          集合（表）名
   * @param obj
   *          插入数据集合
   * 
   */
  public void insert(String collection, DBObject obj) {
    try {
      db.requestStart(); // 相当于开始事物
      getCollection(collection).insert(obj);
    } catch (Exception e) {
      throw new BaseException("mongodb 集合[" + collection + "]执行插入记录失败!", e);
    } finally {
      if (db != null)
        db.requestDone(); // 相当于关闭事物
    }
  }

  /**
   * 给mongoDB 批量插入 给mongoDB 批量插入
   * 
   * @param collection
   * @param list
   *          插入的列表
   */
  public int insertBatch(String collection, List<DBObject> list) {
    int count = 0;
    if (list == null || list.isEmpty()) {
      count = 0;
    }
    try {
      db.requestStart(); // 相当于开始事物
      count = getCollection(collection).insert(list).getN();
    } catch (Exception e) {
      throw new BaseException("mongodb 集合[" + collection + "]执行批量插入记录失败！", e);
    } finally {
      if (db != null)
        db.requestDone(); // 相当于关闭事物
    }
    return count;
  }

  /**
   * mongoDB 根据查询删除数据 mongoDB 根据查询删除数据
   * 
   * @param collection
   * @param whereobj
   *          查询条件
   * 
   */
  public void delete(String collection, DBObject whereobj) {
    try {
      db.requestStart(); // 相当于开始事物
      getCollection(collection).remove(whereobj);
    } catch (Exception e) {
      throw new BaseException("mongodb 集合[" + collection + "]执行删除失败！", e);
    } finally {
      if (db != null)
        db.requestDone(); // 相当于关闭事物
    }
  }

  /**
   * 批量删除记录
   * 
   * @description 批量删除记录
   * @param collection
   * @param list
   *          删除条件列表
   */
  public void deleteBatch(String collection, List<DBObject> list) {

    if (list == null || list.isEmpty()) {
      return;
    }

    for (int i = 0; i < list.size(); i++) {
      delete(collection, list.get(i));
    }

  }

  /**
   * 计算集合总条数
   * 
   * @description 计算集合总条数
   * @param collection
   * @return 集合记录数
   */
  public long getCount(String collection) {
    return getCollection(collection).find().count();
  }

  /**
   * 
   * 计算集合满足条件条数
   * 
   * @description 计算集合满足条件条数
   * @param collection
   * @param whereobj
   *          查询条件
   */
  public long getCount(String collection, DBObject whereobj) {
    return getCollection(collection).getCount(whereobj);
  }

  /**
   * 更新集合记录
   * 
   * @description 更新集合记录
   * @param collection
   * @param whereobj
   *          查询条件
   * @param setFields
   *          更新对象
   */
  public void update(String collection, DBObject whereobj, DBObject setFields) {
    try {
      db.requestStart(); // 相当于开始事物
      getCollection(collection).updateMulti(whereobj, new BasicDBObject("$set", setFields));
    } catch (Exception e) {
      throw new BaseException("mongodb 集合[" + collection + "]执行更新记录失败！", e);
    } finally {
      if (db != null)
        db.requestDone(); // 相当于关闭事物
    }

  }

  /**
   * 查找集合所有对象
   * 
   * @description 查找集合所有对象
   * @param collection
   * @return list
   */
  public List<DBObject> findAll(String collection) {
    return getCollection(collection).find().toArray();
  }

  /**
   * 按顺序查找集合所有对象
   * 
   * @description 按顺序查找集合所有对象
   * @param collection
   *          数据集
   * @param orderBy
   *          排序
   */
  public List<DBObject> findAll(String collection, DBObject orderBy) {
    return getCollection(collection).find().sort(orderBy).toArray();
  }

  /**
   * 查找（返回一个对象）
   * 
   * @description 查找（返回一个对象）
   * @param collection
   * @param whereobj
   *          查询条件
   */
  public DBObject findOne(String collection, DBObject whereobj) {
    return getCollection(collection).findOne(whereobj);
  }

  /**
   * 查找（返回一个对象,指定返回字段）
   * 
   * @description 查找（返回一个对象,指定返回字段）
   * @param collection
   * @param whereobj
   *          查询条件
   * @param fileds
   *          返回字段
   */
  public DBObject findOne(String collection, DBObject whereobj, DBObject fileds) {

    return getCollection(collection).findOne(whereobj, fileds);
  }

  /**
   * 查找返回特定字段（返回一个List<DBObject>）
   * 
   * @description 查找返回特定字段（返回一个List<DBObject>）
   * @param collection
   * @param whereobj
   *          查询条件
   * @param fileds
   *          返回字段
   */
  public List<DBObject> findLess(String collection, DBObject whereobj, DBObject fileds) {

    DBCursor c = getCollection(collection).find(whereobj, fileds);
    if (c != null)
      return c.toArray();
    else
      return null;
  }

  /**
   * 查找返回特定字段（返回一个List<DBObject>,指定集合返回字段）
   * 
   * @description 查找返回特定字段（返回一个List<DBObject>,指定集合返回字段）
   * @param collection
   * @param whereobj
   *          查询条件
   * @param fileds
   *          返回字段
   * @param orderBy
   *          排序
   */
  public List<DBObject> findLess(String collection, DBObject whereobj, DBObject fileds,
      DBObject orderBy) {

    DBCursor c = getCollection(collection).find(whereobj, fileds).sort(orderBy);
    if (c != null)
      return c.toArray();
    else
      return null;
  }

  /**
   * 分页查找集合对象，返回特定字段
   * 
   * @description 分页查找集合对象，返回特定字段
   * @param collection
   * @param whereobj
   *          查询条件
   * @param fileds
   *          返回字段
   * @pageNo 第n页
   * @perPageCount 每页记录数
   */
  public List<DBObject> findLess(String collection, DBObject whereobj, DBObject fileds, int pageNo,
      int perPageCount) {

    return getCollection(collection).find(whereobj, fileds).skip((pageNo - 1) * perPageCount)
        .limit(perPageCount).toArray();
  }

  /**
   * 按顺序分页查找集合对象，返回特定字段
   * 
   * @description 按顺序分页查找集合对象，返回特定字段
   * @param collection
   *          集合
   * @param whereobj
   *          查询条件
   * @param fileds
   *          返回字段
   * @param orderBy
   *          排序
   * @param pageNo
   *          第n页
   * @param perPageCount
   *          每页记录数
   */
  public List<DBObject> findLess(String collection, DBObject whereobj, DBObject fileds,
      DBObject orderBy, int pageNo, int perPageCount) {

    return getCollection(collection).find(whereobj, fileds).sort(orderBy)
        .skip((pageNo - 1) * perPageCount).limit(perPageCount).toArray();
  }

  /**
   * 查找（返回一个List<DBObject>）
   * 
   * @description 查找（返回一个List<DBObject>）
   * @param collection
   * @param whereobj
   *          查询条件
   */
  public List<DBObject> find(String collection, DBObject whereobj) {

    DBCursor c = getCollection(collection).find(whereobj);
    if (c != null)
      return c.toArray();
    else
      return null;
  }

  /**
   * 查找（返回一个List<DBObject>）
   * 
   * @description 查找（返回一个List<DBObject>）
   * @param collection
   * @param whereobj
   *          查询条件
   * @param orderBy
   *          排序
   */
  public List<DBObject> find(String collection, DBObject whereobj, DBObject orderBy) {

    DBCursor c = getCollection(collection).find(whereobj).sort(orderBy);
    if (c != null)
      return c.toArray();
    else
      return null;
  }

  /**
   * 分页查找集合对象（返回一个List<DBObject>）
   * 
   * @description 分页查找集合对象（返回一个List<DBObject>）
   * @param collection
   * @param whereobj
   *          查询条件
   * @pageNo 第n页
   * @perPageCount 每页记录数
   */
  public List<DBObject> find(String collection, DBObject whereobj, int pageNo, int perPageCount) {

    return getCollection(collection).find(whereobj).skip((pageNo - 1) * perPageCount)
        .limit(perPageCount).toArray();
  }

  /**
   * 按顺序分页查找集合对象（返回一个List<DBObject>）
   * 
   * @description 按顺序分页查找集合对象（返回一个List<DBObject>）
   * @param collection
   *          集合
   * @param whereobj
   *          查询条件
   * @param orderBy
   *          排序
   * @param pageNo
   *          第n页
   * @param perPageCount
   *          每页记录数
   */
  public List<DBObject> find(String collection, DBObject whereobj, DBObject orderBy, int pageNo,
      int perPageCount) {

    return getCollection(collection).find(whereobj).sort(orderBy).skip((pageNo - 1) * perPageCount)
        .limit(perPageCount).toArray();
  }

  /**
   * distinct操作
   * 
   * @description distinct操作
   * @param collection
   *          集合
   * @param field
   *          distinct字段名称
   */
  public Object[] distinct(String collection, String field) {

    return getCollection(collection).distinct(field).toArray();
  }

  /**
   * distinct操作
   * 
   * @description distinct操作
   * @param collection
   *          集合
   * @param field
   *          distinct字段名称
   * @param whereobj
   *          查询条件
   */
  public Object[] distinct(String collection, String field, DBObject whereobj) {
    return getCollection(collection).distinct(field, whereobj).toArray();
  }

  /**
   * group分组查询操作，返回结果少于10,000keys时可以使用
   * 
   * @description group分组查询操作，返回结果少于10,000keys时可以使用
   * @param collection
   *          集合
   * @param key
   *          分组查询字段
   * @param whereobj
   *          查询条件
   * @param reduce
   *          reduce Javascript函数，如 function(obj,
   *          out){out.count++;out.csum=obj.c;}
   * @param finalize
   *          reduce function返回结果处理Javascript函数，如
   *          function(out){out.avg=out.csum/out.count;}
   */
  public BasicDBList group(String collection, DBObject key, DBObject whereobj, DBObject initial,
      String reduce, String finalize) {

    return ((BasicDBList) getCollection(collection).group(key, whereobj, initial, reduce, finalize));
  }

  /**
   * group分组查询操作，返回结果大于10,000keys时可以使用，待定是否要
   * 
   * @param collection
   *          集合
   * @param map
   *          映射javascript函数字符串，如 function(){ for(var key in this) {
   *          emit(key,{count:1}) } }
   * @param reduce
   *          reduce Javascript函数字符串，如 function(key,emits){ total=0; for(var i
   *          in emits){ total+=emits[i].count; } return {count:total}; }
   * @param q
   *          分组查询条件
   * @param orderBy
   *          分组查询排序
   */
  public Iterable<DBObject> mapReduce(String collection, String map, String reduce, DBObject q,
      DBObject orderBy) {

    // DBCollection coll = db.getCollection(collection);
    // MapReduceCommand cmd = new MapReduceCommand(coll, map, reduce, null,
    // MapReduceCommand.OutputType.INLINE, q);
    // return coll.mapReduce(cmd).results();
    MapReduceOutput out = getCollection(collection).mapReduce(map, reduce, null, q);
    return out.getOutputCollection().find().sort(orderBy).toArray();
  }

  /**
   * group分组分页查询操作，返回结果大于10,000keys时可以使用，待定是否要
   * 
   * @param collection
   *          集合
   * @param map
   *          映射javascript函数字符串，如 function(){ for(var key in this) {
   *          emit(key,{count:1}) } }
   * @param reduce
   *          reduce Javascript函数字符串，如 function(key,emits){ total=0; for(var i
   *          in emits){ total+=emits[i].count; } return {count:total}; }
   * @param q
   *          分组查询条件
   * @param orderBy
   *          分组查询排序
   * @param pageNo
   *          第n页
   * @param perPageCount
   *          每页记录数
   */
  public List<DBObject> mapReduce(String collection, String map, String reduce, DBObject q,
      DBObject orderBy, int pageNo, int perPageCount) {

    MapReduceOutput out = getCollection(collection).mapReduce(map, reduce, null, q);
    return out.getOutputCollection().find().sort(orderBy).skip((pageNo - 1) * perPageCount)
        .limit(perPageCount).toArray();
  }

  /**
   * group分组查询操作，返回结果大于10,000keys时可以使用
   * 
   * @description group分组查询操作，返回结果大于10,000keys时可以使用
   * @param collection
   *          集合
   * @param map
   *          映射javascript函数字符串，如 function(){ for(var key in this) {
   *          emit(key,{count:1}) } }
   * @param reduce
   *          reduce Javascript函数字符串，如 function(key,emits){ total=0; for(var i
   *          in emits){ total+=emits[i].count; } return {count:total}; }
   * @param outputCollectionName
   *          输出结果表名称
   * @param q
   *          分组查询条件
   * @param orderBy
   *          分组查询排序
   */
  public List<DBObject> mapReduce(String collection, String map, String reduce,
      String outputCollectionName, DBObject q, DBObject orderBy) {

    if (!db.collectionExists(outputCollectionName)) {
      getCollection(collection).mapReduce(map, reduce, outputCollectionName, q);
    }

    return getCollection(outputCollectionName).find(null, new BasicDBObject("_id", false))
        .sort(orderBy).toArray();
  }

  /**
   * group分组分页查询操作，返回结果大于10,000keys时可以使用
   * 
   * @description group分组分页查询操作，返回结果大于10,000keys时可以使用
   * @param collection
   *          集合
   * @param map
   *          映射javascript函数字符串，如 function(){ for(var key in this) {
   *          emit(key,{count:1}) } }
   * @param reduce
   *          reduce Javascript函数字符串，如 function(key,emits){ total=0; for(var i
   *          in emits){ total+=emits[i].count; } return {count:total}; }
   * @param outputCollectionName
   *          输出结果表名称
   * @param q
   *          分组查询条件
   * @param orderBy
   *          分组查询排序
   * @param pageNo
   *          第n页
   * @param perPageCount
   *          每页记录数
   */
  public List<DBObject> mapReduce(String collection, String map, String reduce,
      String outputCollectionName, DBObject q, DBObject orderBy, int pageNo, int perPageCount) {

    if (!db.collectionExists(outputCollectionName)) {
      getCollection(collection).mapReduce(map, reduce, outputCollectionName, q);
    }

    return getCollection(outputCollectionName).find(null, new BasicDBObject("_id", false))
        .sort(orderBy).skip((pageNo - 1) * perPageCount).limit(perPageCount).toArray();
  }

  /**
   * 获取数据库集合（表）操作对象
   * 
   * @description 获取数据库集合（表）操作对象
   * @param collectionName
   * @return
   */
  public DBCollection getCollection(String collectionName) {
    return this.db.getCollection(collectionName);
  }

  /**
   * 获取连接
   * 
   * @description 获取连接
   * @return the db
   */
  public DB getDb() {
    return db;
  }

  /**
   * 给DB 赋值
   * 
   * @description 给DB 赋值
   * @param db
   *          the db to set
   */
  public void setDb(DB db) {
    this.db = db;
    checkDB();
  }

  /**
   * 检验DB 是否可用
   */
  public void checkDB() {
    if (null == db)
      throw new BaseException("获取mongodb数据库连接失败！");
  }

}
